package main

import (
	"flag"
	"gitee.com/pdudo/SampleDNS2/DnsServer"
	"gitee.com/pdudo/SampleDNS2/db"
	_ "gitee.com/pdudo/SampleDNS2/log"
	"gitee.com/pdudo/SampleDNS2/web"
	"gopkg.in/redis.v5"
	"log"
	"net"
	"time"
)

var (
	// help
	help bool

	// config
	config string

	// global
	globalRedisHost string
	globalRedisAuth string
	globalRedisDB int

	// dbs
	dnsTcpUdpBind string
	dnsProxyDNS string
	dnsProxyPort int
	dnsOnlineStatus bool

	// web
	webBind string
	RegisterKeys string
)

func init() {
	// config
	flag.StringVar(&config,"c","","Specify the configuration file")

	// dns
	flag.StringVar(&dnsTcpUdpBind,"dnsBind","0.0.0.0:53","DNS server listening address")
	flag.StringVar(&dnsProxyDNS,"proxyDNSHost","114.114.114.114","Proxy DNS host")
	flag.IntVar(&dnsProxyPort,"proxyDNSPort",53,"Proxy DNS port")
	flag.BoolVar(&dnsOnlineStatus,"dnsOnlineStatus",false,"Print dns online info")

	// global
	flag.StringVar(&globalRedisHost,"redisHost","127.0.0.1:6379","Redis Host")
	flag.StringVar(&globalRedisAuth,"redisAuth","","Redis auth")
	flag.IntVar(&globalRedisDB,"redisDB",0,"Redis DB")

	// web
	flag.StringVar(&webBind,"webBind","0.0.0.0:5001","webBind")
	flag.StringVar(&RegisterKeys,"RegisterKeys","Xle","Register redis keys")

	// help
	flag.BoolVar(&help,"h",false,"Get help")
}


func main() {

	flag.Parse()

	if help {
		flag.Usage()
		return
	}

	if config == "" {
		// global
		db.DnsConf.ConfGlobal.RedisHost = globalRedisHost
		db.DnsConf.ConfGlobal.Auth = globalRedisAuth
		db.DnsConf.ConfGlobal.DB = globalRedisDB

		// dns
		db.DnsConf.ConfDNS.Bind = dnsTcpUdpBind
		db.DnsConf.ConfDNS.ProxyDNS = dnsProxyDNS
		db.DnsConf.ConfDNS.ProxyDNSPort = dnsProxyPort
		db.DnsConf.ConfDNS.OnlineStatus = dnsOnlineStatus

		// web
		db.DnsConf.ConfWeb.Bind = webBind
		db.DnsConf.ConfWeb.RegisterKeys = RegisterKeys
	} else {
		db.DnsConf.LoadConf(config)
	}

	if db.DnsConf.ConfDNS.OnlineStatus {
		go PrintGoprocessCount()
	}

	// 连接Redis
	db.Rdb = redis.NewClient(&redis.Options{
		Addr: db.DnsConf.ConfGlobal.RedisHost,
		Password: db.DnsConf.ConfGlobal.Auth,
		DB: db.DnsConf.ConfGlobal.DB,
	})

	_ , err := db.Rdb.Ping().Result()
	if err != nil {
		log.Panic("connect redis error " , err)
	} else {
		log.Println("connect redis successful" , db.DnsConf.ConfGlobal)
	}

	go web.Web()
	//time.Sleep(3 * time.Second)
	go DnsServerUDPStart()
	DnsServerTCPStart()
}

func DnsServerTCPStart() {
	tcpAddr , err := net.Listen("tcp",db.DnsConf.ConfDNS.Bind)
	if err != nil {
		log.Fatal("DNS Server TCP Start error " , err)
	} else {
		log.Println("DNS Server TCP Start successful ", db.DnsConf.ConfDNS.Bind)
	}

	for {
		conn , err := tcpAddr.Accept()
		if err != nil {
			log.Println("TCP Accept error " , err)
		}

		var user DnsServer.DnsUser
		user.IP = conn.RemoteAddr().String()

		go user.TCPStart(conn)
	}
}

func DnsServerUDPStart() {
	udpAddr , _ := net.ResolveUDPAddr("udp4",db.DnsConf.ConfDNS.Bind)

	conn , err := net.ListenUDP("udp",udpAddr)
	if err != nil {
		log.Panic("Listen UDP error " , err)
	} else {
		log.Println("DNS Server UDP Start successful " , db.DnsConf.ConfDNS.Bind)
	}

	for {
		buf := make([]byte,512)

		n , connUDP , err := conn.ReadFromUDP(buf)
		if err != nil {
			log.Println("from conn read buf error " , err)
		}

		var user DnsServer.DnsUser
		go user.UDPStart(conn,connUDP,buf[:n])
	}
}

func PrintGoprocessCount() {
	t1 := time.NewTicker(30 * time.Second)

	for {
		select {
		case <-t1.C:
			log.Println("DNS client Count " , DnsServer.ProcessID , ",DNS access Sum count: " , DnsServer.SumCount)
		}
	}
}
